﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace MathService
{
    /// <summary>ОБъект, представляющий метод сравнения двух объектов типа <typeparamref name="T"/>, задаваемый lambda-выражением</summary>
    /// <typeparam name="T">Тип сравниваемых объектов</typeparam>
    public class LambdaComparer<T> : IComparer<T>
    {
        /* ------------------------------------------------------------------------------------------ */

        private readonly Func<T, T, int> f_Comparer;

        /* ------------------------------------------------------------------------------------------ */

        public LambdaComparer(Func<T, T, int> Comparer)
        {
            Contract.Requires(Comparer != null);
            Contract.Ensures(f_Comparer != null);

            f_Comparer = Comparer;
        }

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>
        /// Сравнивает два объекта и возвращает значение, показывающее, что один объект меньше или больше другого или равен ему.
        /// </summary>
        /// <returns>
        /// Значение Условие Меньше нуля<paramref name="x"/> меньше, чем <paramref name="y"/>.Нуль<paramref name="x"/> равно <paramref name="y"/>.Больше нуля<paramref name="x"/> больше, чем <paramref name="y"/>.
        /// </returns>
        /// <param name="x">Первый сравниваемый объект.</param><param name="y">Второй сравниваемый объект.</param>
        public int Compare(T x, T y) { return f_Comparer(x, y); }

        /* ------------------------------------------------------------------------------------------ */
    }

    public class LambdaEqualityComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> f_Comparer;
        private readonly Func<T, int> f_HashFunction;

        public LambdaEqualityComparer(Func<T, T, bool> Comparer, Func<T, int> HashFunction = null)
        {
            Contract.Requires(Comparer != null);
            Contract.Ensures(f_Comparer == Comparer);
            Contract.Ensures(f_HashFunction != null);

            f_Comparer = Comparer;
            f_HashFunction = HashFunction ?? (o => o.GetHashCode());
        }

        /// <summary>Определяет, равны ли два указанных объекта.</summary>
        /// <returns>Значение true, если указанные объекты равны; в противном случае — значение false.</returns>
        /// <param name="x">Первый сравниваемый объект типа <typeparam name="T"/>.</param>
        /// <param name="y">Второй сравниваемый объект типа <typeparam name="T"/>.</param>
        public bool Equals(T x, T y) { return f_Comparer(x, y); }

        /// <summary>Возвращает хэш-код указанного объекта.</summary>
        /// <returns>Хэш-код указанного объекта.</returns>
        /// <param name="obj">Объект <see cref="T:System.Object"/>, для которого должен быть возвращен хэш-код.</param>
        /// <exception cref="T:System.ArgumentNullException">Тип <paramref name="obj"/> является ссылочным типом, значением <paramref name="obj"/> является null.</exception>
        public int GetHashCode(T obj) { return f_HashFunction(obj); }
    }
}
